/*
 *  network_test.c
 *  
 *
 *  Created by Min Su on 3/21/12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */
 
 #include "syscall.h"
 #include "userlib.h"
 
 
 void wait(int time) {
	int i;
	for (i=0; i<time; i++) {
		Yield();
	}
}


 int lockCreate() {
	int arg[1];
	int testLock = CreateServerLock("testLock", sizeof("testLock"));
	arg[0] = testLock;
	myprintf("Lock %d created\n", arg, 1);
	return testLock;
}
int lockCreate2() {
	int arg[1];
	int testLock = CreateServerLock("testLock2", sizeof("testLock2"));
	arg[0] = testLock;
	myprintf("Lock %d created\n", arg, 1);
	return testLock;
}

void lockDestory(int testLock) {
	int arg[1];
	DestroyServerLock(testLock);
	arg[0] = testLock;
	myprintf("Lock %d destoried\n", arg, 1);
}

void lockAcquire(int testLock) {
	int arg[1];
	AcquireServerLock(testLock);
	arg[0] = testLock;
	myprintf("Lock %d aquired\n", arg, 1);
}


void lockRelease(int testLock) {
	int arg[1];
	ReleaseServerLock(testLock);
	arg[0] = testLock;
	myprintf("Lock %d released\n", arg, 1);
}

void lockBadAcquire(int testLock) {
	int arg[1];
	arg[0] = -2;
	myprintf("Try to acquire an illegal lock %d\n", arg, 1);
	AcquireServerLock(-2);
	arg[0] = testLock+1;
	myprintf("Try to acquire an illegal lock %d\n", arg, 1);
	AcquireServerLock(testLock+1);
	arg[0] = testLock;
	myprintf("Try to acquire a legal lock %d\n", arg, 1);
	AcquireServerLock(testLock);
}

 int CVCreate() {
	int arg[1];
	int testCV = CreateServerCondition("testCV", sizeof("testCV"));
	arg[0] = testCV;
	myprintf("CV %d created\n", arg, 1);
	return testCV;
}

void CVSignal(int testlock, int testCV) {
	int arg[2];
	SignalServerCondition(testCV, testlock);
	arg[0] = testCV;
	arg[1] = testlock;
	myprintf("CV %d signal lock %s\n", arg, 2);
}

void CVWait(int testlock, int testCV) {
	int arg[2];
	WaitServerCondition(testCV, testlock);
	arg[0] = testCV;
	arg[1] = testlock;
	myprintf("CV %d wait lock %s\n", arg, 2);
}

void CVBroadcast(int testlock, int testCV) {
	int arg[2];
	BroadcastServerCondition(testCV, testlock);
	arg[0] = testCV;
	arg[1] = testlock;
	myprintf("CV %d Broadcast lock %s\n", arg, 2);
}

int MVcreate1(int size) {
	int arg[2];
	int mvnum1 = CreateMV("MV1", sizeof("MV1"), size);
	arg[0] = mvnum1;
	arg[1] = size;
	myprintf("MV %d has size %d\n", arg, 2);
	return mvnum1;
}

int MVcreate2(int size) {
	int arg[2];
	int mvnum2 = CreateMV("MV2", sizeof("MV1"), size);
	arg[0] = mvnum2;
	arg[1] = size;
	myprintf("MV %d has size %d\n", arg, 2);
	return mvnum2;
}

void MVget(int id, int slot) {
	int arg[2];
	int mvvalue = GetMVValue(id, slot);
	arg[1] = mvvalue;
	arg[0] = id;
	myprintf("MV %d has value %d\n", arg, 2);
}

void MVset(int id, int slot, int value) {
	int arg[3];
	SetMVValue(id, slot, value);
	arg[1] = value;
	arg[0] = id;
	arg[2] = slot;
	myprintf("MV %d has set %d to slot %d\n", arg, 3);
}

void lockTest() {
	int arg[2];
	int testLock = CreateServerLock("testLock", sizeof("testLock"));
	arg[0] = testLock;
	myprintf("Lock %d created\n", arg, 1);
	arg[0] = -2;
	myprintf("Try to acquire an illegal lock %d\n", arg, 1);
	AcquireServerLock(-2);
	arg[0] = testLock+1;
	myprintf("Try to acquire an illegal lock %d\n", arg, 1);
	AcquireServerLock(testLock+1);
	arg[0] = testLock;
	myprintf("Try to acquire a legal lock %d\n", arg, 1);
	AcquireServerLock(testLock);
	
	arg[0] = -2;
	myprintf("Try to release an illegal lock %d\n", arg, 1);
	ReleaseServerLock(-2);
	arg[0] = testLock+1;
	myprintf("Try to release an illegal lock %d\n", arg, 1);
	ReleaseServerLock(testLock+1);
	arg[0] = testLock;
	myprintf("Try to release a legal lock %d\n", arg, 1);
	ReleaseServerLock(testLock);
	DestroyServerLock(testLock);
}

/* Test 1 */
int t1_l1;	/* the lock tested in Test 1 */

/* test 1 client 1
 * This is the rightful lock owner
 */
void t1_c1() {
	int i;
	int arg[2];
	AcquireServerLock(t1_l1);
	arg[0] = 1;
	arg[1] = t1_l1;
	myprintf("t1_c%d: Acquired Lock %d, waiting for c3\n", arg, 2);
	myprintf("t1_c%d: working with lock %d\n", arg, 2);
	wait(5);
	myprintf("t1_c%d: Releasing lock %d\n", arg, 2);
	ReleaseServerLock(t1_l1);
}

/* test 1 client 2
 * This thread will wait on the held lock
 */
void t1_c2() {
	int i;
	int arg[2];
	arg[0] = 2;
	arg[1] = t1_l1;
	myprintf("t1_c%d: trying to acquire lock %d\n", arg, 2);
	AcquireServerLock(t1_l1);
	myprintf("t1_c%d: Acquired lock %d\n", arg, 2);
	wait(5);
	myprintf("t1_t%d: Releasing lock %d\n", arg, 2);
	ReleaseServerLock(t1_l1);
}

/* test 1 thread 3
 * This thread will try to release the lock illegally
 */
void t1_c3() {
	int i;
	int arg[2];
	arg[0] = 3;
	arg[1] = t1_l1;
	wait(3);
	for (i=0; i<3; i++) {
		myprintf("t1_c%d: trying to release lock %d\n", arg, 2);
		ReleaseServerLock(t1_l1);
	}
}

/* Test 2 */

int t2_l1;	/* For mutual exclusion */
int t2_cv1;	/* The condition variable to test */

/* test 2 thread 1
 * This thread will signal a variable with nothing waiting
 */
void t2_c1() {
	int arg[3];
	arg[0] = 1;
	arg[1] = t2_l1;
	arg[2] = t2_cv1;
	AcquireServerLock(t2_l1);
	myprintf("t2_c%d: Lock %d acquired, signalling %d\n", arg, 3);
	SignalServerCondition(t2_cv1, t2_l1);
	myprintf("t2_t%d: Releasing Lock %d\n", arg, 3);
	ReleaseServerLock(t2_l1);
}

/* test 2 thread 2
 * This thread will wait on a pre-signalled variable
 */
void t2_t2() {
	int arg[3];
	arg[0] = 2;
	arg[1] = t2_l1;
	arg[2] = t2_c1;
	wait(5);
	AcquireLock(t2_l1);
	myprintf("t2_t%d: Lock %d acquired, waiting on %d\n", arg, 3);
	WaitCondition(t2_c1, t2_l1);
	myprintf("t2_t%d: Releasing Lock %d\n", arg, 3);
	ReleaseLock(t2_l1);
	Exit(0);
}

/* Test 3 */
int t3_l1;	/* For mutual exclusion */
int t3_c1;	/* The condition variable to test */
int t3_l2;
int num = 0;

/* t3_waiter()
 * These threads will wait on the t3_c1 condition variable.
 * Only one t3_waiter will be released
 */
void t3_waiter() {
	int arg[3];
	AcquireLock(t3_l1);
	arg[0] = num ++;
	ReleaseLock(t3_l1);
	arg[1] = t3_l2;
	arg[2] = t3_c1;
	
	AcquireLock(t3_l2);
	myprintf("t3_waiter%d: Lock %d acquired, waiting on %d\n", arg, 3);
	WaitCondition(t3_c1, t3_l2);
	arg[1] = t3_c1;
	myprintf("t3_waiter%d: free from %d\n", arg, 2);
	ReleaseLock(t3_l2);
	Exit(0);
}

/* t3_signaller()
 * This thread will signal the t3_c1 condition variable.
 * Only one t3_signaller will be released
 */
void t3_signaller() {
	int arg[3];
	arg[0] = 0;
	arg[1] = t3_l2;
	arg[2] = t3_c1;
	wait(5);
	AcquireLock(t3_l2);
	myprintf("t3_signaller%d: Lock %d acquired, signalling %d\n", arg, 3);
	SignalCondition(t3_c1, t3_l2);
	ReleaseLock(t3_l2);
	Exit(0);
}

/* Test 4 */

int t4_l1;
int t4_l2;
int t4_c1;
int num4 = 0;

/* t4_waiter()
 * These threads will wait on the t4_c1 condition variable.
 * All t4_waiters will be released
 */
void t4_waiter() {
	int arg[3];
	AcquireLock(t4_l1);
	arg[0] = num4 ++;
	ReleaseLock(t4_l1);
	arg[1] = t4_l2;
	arg[2] = t4_c1;
	
	AcquireLock(t4_l2);
	myprintf("t4_waiter%d: Lock %d acquired, waiting on %d\n", arg, 3);
	WaitCondition(t4_c1, t4_l2);
	arg[1] = t4_c1;
	myprintf("t4_waiter%d: free from %d\n", arg, 2);
	ReleaseLock(t4_l2);
	Exit(0);
}

/* t4_signaller()
 * This thread will broadcast the t4_c1 condition variable.
 * All t4_waiter will be released
 */
void t4_signaller() {
	int arg[3];
	arg[0] = 0;
	arg[1] = t4_l2;
	arg[2] = t4_c1;
	wait(5);
	AcquireLock(t4_l2);
	myprintf("t4_signaller%d: Lock %d acquired, broadcasting %d\n", arg, 3);
	BroadcastCondition(t4_c1, t4_l2);
	ReleaseLock(t4_l2);
	Exit(0);
}

/* Test 5 */

int t5_l1;	/* For mutual exclusion */
int t5_l2;	/* Second lock for the bad behavior */
int t5_c1;	/* The condition variable to test */

/* t5_t1() -- test 5 thread 1
 * This thread will wait on a condition under t5_l1
 */
void t5_t1() {
	int arg[3];
	arg[0] = 1;
	arg[1] = t5_l1;
	arg[2] = t5_c1;
	AcquireLock(t5_l1);
	myprintf("t5_t%d: Lock %d acquired, waiting on %d\n", arg, 3);
	WaitCondition(t5_c1, t5_l1);
	ReleaseLock(t5_l1);
	Exit(0);
}

/* t5_t2() -- test 5 thread 2
 * This thread will wait on a t5_c1 condition under t5_l2, which is
 * a Fatal error
 */
void t5_t2() {
	int arg[3];
	arg[0] = 2;
	arg[1] = t5_l2;
	arg[2] = t5_c1;
	wait(5); /* Wait for t5_t1 to get into the monitor */
	AcquireLock(t5_l1);
	AcquireLock(t5_l2);
	myprintf("t5_t%d: Lock %d acquired, signalling on %d\n", arg, 3);
	SignalCondition(t5_c1, t5_l2);
	myprintf("t5_t%d: Releasing Lock %d\n", arg, 2);
	ReleaseLock(t5_l2);
	arg[1] = t5_l1;
	myprintf("t5_t%d: Releasing Lock %d\n", arg, 2);
	ReleaseLock(t5_l1);
	Exit(0);
}

/* Test 6 */

int t6_l1;	/* Test destroy lock */

/* t6_t1() -- test 6 thread 1
 * This thread will acquire a lock and destory it before release;
 */
void t6_t1() {
	int arg[2];
	arg[0] = 1;
	arg[1] = t6_l1;
	AcquireLock(t6_l1);
	myprintf("t6_t%d: Lock %d acquired\n", arg, 2);
	wait(5);
	myprintf("t6_t%d: Delete the lock %d\n", arg, 2);
	DestroyLock(t6_l1);
	myprintf("t6_t%d: Release the lock %d\n", arg, 2);
	ReleaseLock(t6_l1);
	Exit(0);
}

/* t6_t2() -- test 6 thread 2
 * This thread will still get the lock after t6_t1 destroy the lock
 */
void t6_t2() {
	int arg[2];
	arg[0] = 2;
	arg[1] = t6_l1;
	wait(3);
	myprintf("t6_t%d: Try to acquire lock %d\n", arg, 2);
	AcquireLock(t6_l1);
	myprintf("t6_t%d: Lock %d acquired\n", arg, 2);
	wait(2);
	myprintf("t6_t%d: Release the lock %d\n", arg, 2);
	ReleaseLock(t6_l1);
	Exit(0);
}

/* Test 7 */
int t7_l1;	/* the lock used by CV */
int t7_c1;	/* the condition variable will be deleted before signal */

/* t7_t1() -- test 7 thread 1
 * This thread will wait on a deleted condition variable
 */
void t7_t1() {
	int arg[3];
	arg[0] = 1;
	arg[1] = t7_l1;
	arg[2] = t7_c1;
	AcquireLock(t7_l1);
	myprintf("t7_t%d: Lock %d acquired, wait on Condition %d\n", arg, 3);
	WaitCondition(t7_c1, t7_l1);
	arg[1] = t7_c1;
	arg[2] = t7_l1;
	myprintf("t7_t%d: Free from %d, Rlease Lock %d\n", arg, 3);
	ReleaseLock(t7_l1);
	Exit(0);
}

/* t7_t2() -- test 7 thread 2
 * This thread will delete the condition variable 
 */
void t7_t2() {
	int arg[2];
	arg[0] = 2;
	arg[1] = t7_c1;
	wait(5);
	myprintf("t7_t%d: Delete the Condition %d\n", arg, 2);
	DestroyCondition(t7_c1);
	Exit(0);
}

/* t7_t3() -- test 7 thread 3
 * This thread will signal the waiter
 */
void t7_t3() {
	int arg[3];
	arg[0] = 3;
	arg[1] = t7_l1;
	arg[2] = t7_c1;
	wait(10);
	AcquireLock(t7_l1);
	myprintf("t7_t%d: Lock %d acquired, signal Condition %d\n", arg, 3);
	SignalCondition(t7_c1, t7_l1);
	myprintf("t7_t%d: Rlease Lock %d\n", arg, 2);
	ReleaseLock(t7_l1);
	Exit(0);
}

int main() {
	int input;
	int testlock;
	int testCV;
	int MV;
	int input1;
	int input2;
	int input3;
	int aaa;
	myprintf("Test guideline:\n", 0, 0);
	myprintf("1. test 1: This Client act as a main test client in test 1, it create locks and acquire it.\n", 0, 0);
	myprintf("2. test 2: Two or more clients create the same lock\n", 0, 0);
	myprintf("3. test 3: \n", 0, 0);
	myprintf("4. \n", 0, 0);
	myprintf("5. \n", 0, 0);
	myprintf("6. .\n", 0, 0);
	myprintf("7.  \n", 0, 0);
	myprintf("8. Quit. \n", 0, 0);
	myprintf("Please enter the number 1-8 corresponding to the above options:", 0, 0);
	while(1){
	input=myscanf();
	if(input==1){
		testlock = lockCreate();
	}
	if(input == 2){
		lockTest();
	}
	if(input == 3){
		lockAcquire(testlock);
	}
	if(input == 4){
		lockRelease(testlock);
	}
	if(input == 5){
		testCV = CVCreate();
	}
	if(input == 6){
		CVSignal(testlock+1, testCV);
	}
	if(input == 7){
		CVWait(testlock+1, testCV);
	}
	if(input == 8){
		CVBroadcast(testlock, testCV);
	}
	if(input == 9){
		myprintf("Please enter the value", 0, 0);
    input=myscanf();
	}
/*
	if(input == 6){
		input1=myscanf();
		MV = MVcreate1(input1);
	}
	if(input == 7){
		input2=myscanf();
		MV = MVcreate2(input2);
	}
	if(input == 8){
    input1=myscanf();
    input2=myscanf();
		MVset(MV, input1, input2);
	}
	if(input == 9){
    input3=myscanf();
		MVget(MV, input3);
	}
	*/
	
	
	
}	
	return 0;
}